import * as crypto from 'crypto';

import {
  main,
  type FirefliesMeetingData,
  type FirefliesWebhookPayload,
} from '../actions/receive-fireflies-notes';

// Helper to generate HMAC signature
const generateHMACSignature = (body: string, secret: string): string => {
  const signature = crypto
    .createHmac('sha256', secret)
    .update(body, 'utf8')
    .digest('hex');
  return `sha256=${signature}`;
};

// Mock raw Fireflies API response with full summary (before transformation)
const mockFirefliesApiResponseWithSummary = {
  id: 'test-meeting-001',
  title: 'Product Demo with Client',
  date: '2024-11-02T14:00:00Z',
  duration: 1800,
  participants: [
    'Sarah Sales <sales@company.com>',
    'John Client <client@customer.com>',
  ],
  organizer_email: 'sales@company.com',
  summary: {
    action_items: [
      'Follow up with pricing proposal by Friday',
      'Schedule technical deep-dive next week',
      'Share case studies from similar clients',
    ],
    keywords: ['product demo', 'pricing', 'technical requirements', 'integration'],
    overview: 'Successful product demonstration with positive client feedback. Client expressed strong interest in the enterprise plan and requested technical documentation for their IT team.',
    gist: 'Product demo went well, client interested in enterprise plan, next steps identified',
    topics_discussed: ['product features', 'pricing discussion', 'integration capabilities', 'support options'],
    meeting_type: 'Sales Call',
    bullet_gist: '• Demonstrated core product features\n• Discussed enterprise pricing\n• Addressed integration questions',
  },
  sentiments: {  // Note: Raw API has sentiments at top level, not in analytics
    positive_pct: 75,
    negative_pct: 10,
    neutral_pct: 15,
  },
  transcript_url: 'https://app.fireflies.ai/transcript/test-001',
  video_url: 'https://app.fireflies.ai/recording/test-001',
  summary_status: 'completed',
};

// Transformed meeting data (after fetchFirefliesMeetingData processes it)
const mockMeetingWithFullSummary: FirefliesMeetingData = {
  id: 'test-meeting-001',
  title: 'Product Demo with Client',
  date: '2024-11-02T14:00:00Z',
        duration: 1800,
  participants: [
    { email: 'sales@company.com', name: 'Sarah Sales' },
    { email: 'client@customer.com', name: 'John Client' },
  ],
  organizer_email: 'sales@company.com',
  summary: {
    action_items: [
      'Follow up with pricing proposal by Friday',
      'Schedule technical deep-dive next week',
      'Share case studies from similar clients',
    ],
    keywords: ['product demo', 'pricing', 'technical requirements', 'integration'],
    overview: 'Successful product demonstration with positive client feedback. Client expressed strong interest in the enterprise plan and requested technical documentation for their IT team.',
    gist: 'Product demo went well, client interested in enterprise plan, next steps identified',
    topics_discussed: ['product features', 'pricing discussion', 'integration capabilities', 'support options'],
    meeting_type: 'Sales Call',
    bullet_gist: '• Demonstrated core product features\n• Discussed enterprise pricing\n• Addressed integration questions',
  },
  analytics: {
    sentiments: {
      positive_pct: 75,
      negative_pct: 10,
      neutral_pct: 15,
    },
  },
  transcript_url: 'https://app.fireflies.ai/transcript/test-001',
  recording_url: 'https://app.fireflies.ai/recording/test-001',
  summary_status: 'completed',
};

// Mock raw API response without summary (processing)
const mockFirefliesApiResponseWithoutSummary = {
  id: 'test-meeting-002',
  title: 'Team Standup',
  date: '2024-11-02T15:00:00Z',
  duration: 900,
  participants: [
    'Alice Developer <dev1@company.com>',
    'Bob Developer <dev2@company.com>',
  ],
  organizer_email: 'dev1@company.com',
  summary: {
    action_items: [],
    keywords: [],
    overview: '',
    gist: '',
    topics_discussed: [],
  },
  transcript_url: 'https://app.fireflies.ai/transcript/test-002',
  summary_status: 'processing',
};

// Mock meeting data without summary (processing) - currently unused but kept for reference
const _mockMeetingWithoutSummary = {
  id: 'test-meeting-002',
  title: 'Team Standup',
  date: '2024-11-02T15:00:00Z',
  duration: 900,
  participants: [
    { email: 'dev1@company.com', name: 'Alice Developer' },
    { email: 'dev2@company.com', name: 'Bob Developer' },
  ],
  organizer_email: 'dev1@company.com',
  summary: {
    action_items: [],
    keywords: [],
    overview: '',
    gist: '',
    topics_discussed: [],
  },
  transcript_url: 'https://app.fireflies.ai/transcript/test-002',
  summary_status: 'processing',
};

// Mock raw API response for team meeting
const mockFirefliesApiResponseTeamMeeting = {
  ...mockFirefliesApiResponseWithSummary,
  id: 'test-team-003',
  title: 'Sprint Planning',
  participants: [
    'Alice Scrum <scrum@company.com>',
    'Bob Developer <dev1@company.com>',
    'Carol Coder <dev2@company.com>',
    'David QA <qa@company.com>',
  ],
  summary: {
    ...mockFirefliesApiResponseWithSummary.summary,
    meeting_type: 'Sprint Planning',
  },
};

// Mock team meeting with multiple participants (transformed) - currently unused but kept for reference
const _mockTeamMeeting = {
  ...mockMeetingWithFullSummary,
  id: 'test-team-003',
  title: 'Sprint Planning',
        participants: [
    { email: 'scrum@company.com', name: 'Alice Scrum' },
    { email: 'dev1@company.com', name: 'Bob Developer' },
    { email: 'dev2@company.com', name: 'Carol Coder' },
    { email: 'qa@company.com', name: 'David QA' },
  ],
  summary: {
    ...mockMeetingWithFullSummary.summary,
    meeting_type: 'Sprint Planning',
  },
};

// Mock environment variables
const originalEnv = process.env;

beforeEach(() => {
  process.env = {
    ...originalEnv,
    FIREFLIES_WEBHOOK_SECRET: 'test_webhook_secret',
    FIREFLIES_API_KEY: 'test_fireflies_api_key',
    TWENTY_API_KEY: 'test_twenty_api_key',
    SERVER_URL: 'http://localhost:3000',
    AUTO_CREATE_CONTACTS: 'true',
    DEBUG_LOGS: 'false',
    FIREFLIES_SUMMARY_STRATEGY: 'immediate_with_retry',
    FIREFLIES_RETRY_ATTEMPTS: '3',
    FIREFLIES_RETRY_DELAY: '1000',
  };
});

afterEach(() => {
  process.env = originalEnv;
  jest.clearAllMocks();
});

describe('Fireflies Webhook Integration v2', () => {
  describe('Webhook Authentication', () => {
    it('should verify HMAC SHA-256 signature from x-hub-signature header', async () => {
      const payload: FirefliesWebhookPayload = {
        meetingId: 'test-meeting-001',
        eventType: 'Transcription completed',
      };

      const body = JSON.stringify(payload);
      const signature = generateHMACSignature(body, 'test_webhook_secret');

      // Mock Fireflies API
      global.fetch = jest.fn().mockImplementation((url: string) => {
        if (url === 'https://api.fireflies.ai/graphql') {
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({
              data: {
                transcript: mockFirefliesApiResponseWithSummary, // Use raw API format
              },
            }),
          });
        }
        // Twenty API mocks
        return Promise.resolve({
          ok: true,
          json: () => Promise.resolve({
            data: {
              meetings: { edges: [] },
              people: { edges: [] },
              createPerson: { id: 'new-person-id' },
              createNote: { id: 'new-note-id' },
              createMeeting: { id: 'new-meeting-id' },
            },
          }),
        });
      });

      const result = await main(payload, { 'x-hub-signature': signature, body });

      expect(result.success).toBe(true);
    });

    it('should reject requests with invalid signature', async () => {
      const payload: FirefliesWebhookPayload = {
        meetingId: 'test-meeting-001',
        eventType: 'Transcription completed',
      };

      const body = JSON.stringify(payload);
      const invalidSignature = 'sha256=invalid_signature_here';

      const result = await main(payload, { 'x-hub-signature': invalidSignature, body });

      expect(result.success).toBe(false);
      expect(result.errors).toContain('Invalid webhook signature');
    });

    it('should reject requests without signature header', async () => {
      const payload: FirefliesWebhookPayload = {
        meetingId: 'test-meeting-001',
        eventType: 'Transcription completed',
      };

      const result = await main(payload, {});

      expect(result.success).toBe(false);
      expect(result.errors).toContain('Invalid webhook signature');
    });

    it('should reject requests with missing webhook secret env var', async () => {
      delete process.env.FIREFLIES_WEBHOOK_SECRET;

      const payload: FirefliesWebhookPayload = {
        meetingId: 'test-meeting-001',
        eventType: 'Transcription completed',
      };

      const result = await main(payload, {});

      expect(result.success).toBe(false);
    });
  });

  describe('Fireflies GraphQL Integration', () => {
    it('should fetch meeting data from Fireflies API', async () => {
      const payload: FirefliesWebhookPayload = {
        meetingId: 'test-meeting-001',
        eventType: 'Transcription completed',
      };

      const body = JSON.stringify(payload);
      const signature = generateHMACSignature(body, 'test_webhook_secret');

      const firefliesApiMock = jest.fn();

      global.fetch = jest.fn().mockImplementation((url: string) => {
        if (url === 'https://api.fireflies.ai/graphql') {
          firefliesApiMock();
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({
              data: {
                transcript: mockFirefliesApiResponseWithSummary, // Use raw API format
              },
            }),
          });
        }
        // Twenty API mocks
        return Promise.resolve({
          ok: true,
          json: () => Promise.resolve({
            data: {
              meetings: { edges: [] },
              people: { edges: [] },
              createPerson: { id: 'new-person-id' },
              createNote: { id: 'new-note-id' },
              createMeeting: { id: 'new-meeting-id' },
            },
          }),
        });
      });

      const result = await main(payload, { 'x-hub-signature': signature, body });

      expect(firefliesApiMock).toHaveBeenCalled();
      expect(result.success).toBe(true);
    });

    it('should handle Fireflies API fetch failures gracefully', async () => {
      const payload: FirefliesWebhookPayload = {
        meetingId: 'test-meeting-001',
        eventType: 'Transcription completed',
      };

      const body = JSON.stringify(payload);
      const signature = generateHMACSignature(body, 'test_webhook_secret');

      global.fetch = jest.fn().mockImplementation((url: string) => {
        if (url === 'https://api.fireflies.ai/graphql') {
          return Promise.reject(new Error('Fireflies API unavailable'));
        }
        return Promise.resolve({ ok: true, json: () => Promise.resolve({ data: {} }) });
      });

      const result = await main(payload, { 'x-hub-signature': signature, body });

      expect(result.success).toBe(false);
      expect(result.errors?.[0]).toContain('Fireflies API');
    });

    it('should handle malformed GraphQL responses', async () => {
      const payload: FirefliesWebhookPayload = {
        meetingId: 'test-meeting-001',
        eventType: 'Transcription completed',
      };

      const body = JSON.stringify(payload);
      const signature = generateHMACSignature(body, 'test_webhook_secret');

      global.fetch = jest.fn().mockImplementation((url: string) => {
        if (url === 'https://api.fireflies.ai/graphql') {
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({
              data: { malformed: 'response' },
            }),
          });
        }
        return Promise.resolve({ ok: true, json: () => Promise.resolve({ data: {} }) });
      });

      const result = await main(payload, { 'x-hub-signature': signature, body });

      expect(result.success).toBe(false);
      expect(result.errors?.[0]).toContain('Invalid response from Fireflies API');
    });
  });

  describe('Summary Processing', () => {
    it('should create complete records when summary is ready', async () => {
      const payload: FirefliesWebhookPayload = {
        meetingId: 'test-meeting-001',
        eventType: 'Transcription completed',
      };

      const body = JSON.stringify(payload);
      const signature = generateHMACSignature(body, 'test_webhook_secret');

      global.fetch = jest.fn().mockImplementation((url: string) => {
        if (url === 'https://api.fireflies.ai/graphql') {
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({
              data: { transcript: mockFirefliesApiResponseWithSummary }, // Use raw API format
            }),
          });
        }
        // Twenty API mocks
        return Promise.resolve({
          ok: true,
          json: () => Promise.resolve({
            data: {
              meetings: { edges: [] },
              people: { edges: [] },
              createPerson: { id: 'new-person-id' },
              createNote: { id: 'new-note-id' },
              createMeeting: { id: 'new-meeting-id' },
            },
          }),
        });
      });

      const result = await main(payload, { 'x-hub-signature': signature, body });

      expect(result.success).toBe(true);
      expect(result.summaryReady).toBe(true);
      expect(result.actionItemsCount).toBe(3);
      expect(result.sentimentScore).toBeCloseTo(0.75, 2); // Use toBeCloseTo for floating point comparison
      expect(result.meetingType).toBe('Sales Call');
      expect(result.keyTopics).toEqual(['product features', 'pricing discussion', 'integration capabilities', 'support options']);
    });

    it('should create basic records when summary is pending', async () => {
      const payload: FirefliesWebhookPayload = {
        meetingId: 'test-meeting-002',
        eventType: 'Transcription completed',
      };

      const body = JSON.stringify(payload);
      const signature = generateHMACSignature(body, 'test_webhook_secret');

      global.fetch = jest.fn().mockImplementation((url: string) => {
        if (url === 'https://api.fireflies.ai/graphql') {
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({
              data: { transcript: mockFirefliesApiResponseWithoutSummary }, // Use raw API format
            }),
          });
        }
        // Twenty API mocks
        return Promise.resolve({
          ok: true,
          json: () => Promise.resolve({
            data: {
              meetings: { edges: [] },
              people: { edges: [] },
              createPerson: { id: 'new-person-id' },
              createNote: { id: 'new-note-id' },
              createMeeting: { id: 'new-meeting-id' },
            },
          }),
        });
      });

      const result = await main(payload, { 'x-hub-signature': signature, body });

      expect(result.success).toBe(true);
      expect(result.summaryPending).toBe(true);
      expect(result.noteIds || result.meetingId).toBeDefined();
    });

    it('should retry summary fetch with exponential backoff', async () => {
      const payload: FirefliesWebhookPayload = {
        meetingId: 'test-meeting-003',
        eventType: 'Transcription completed',
      };

      const body = JSON.stringify(payload);
      const signature = generateHMACSignature(body, 'test_webhook_secret');

      let attemptCount = 0;

      global.fetch = jest.fn().mockImplementation((url: string) => {
        if (url === 'https://api.fireflies.ai/graphql') {
          attemptCount++;
          // First two attempts return no summary, third returns full summary
          if (attemptCount < 3) {
            return Promise.resolve({
              ok: true,
              json: () => Promise.resolve({
                data: { transcript: mockFirefliesApiResponseWithoutSummary }, // Use raw API format
              }),
            });
          }
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({
              data: { transcript: mockFirefliesApiResponseWithSummary }, // Use raw API format
            }),
          });
        }
        // Twenty API mocks
        return Promise.resolve({
          ok: true,
          json: () => Promise.resolve({
            data: {
              meetings: { edges: [] },
              people: { edges: [] },
              createPerson: { id: 'new-person-id' },
              createNote: { id: 'new-note-id' },
              createMeeting: { id: 'new-meeting-id' },
            },
          }),
        });
      });

      const result = await main(payload, { 'x-hub-signature': signature, body });

      expect(attemptCount).toBe(3);
      expect(result.success).toBe(true);
      expect(result.summaryReady).toBe(true);
    });

    it('should handle immediate_only strategy with single fetch attempt', async () => {
      const payload: FirefliesWebhookPayload = {
        meetingId: 'test-meeting-004',
        eventType: 'Transcription completed',
      };

      const body = JSON.stringify(payload);
      const signature = generateHMACSignature(body, 'test_webhook_secret');

      let fetchCount = 0;

      global.fetch = jest.fn().mockImplementation((url: string) => {
        if (url === 'https://api.fireflies.ai/graphql') {
          fetchCount++;
          // Return summary not ready
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({
              data: { transcript: mockFirefliesApiResponseWithoutSummary },
            }),
          });
        }
        // Twenty API mocks
        return Promise.resolve({
          ok: true,
          json: () => Promise.resolve({
            data: {
              meetings: { edges: [] },
              people: { edges: [] },
              createPerson: { id: 'new-person-id' },
              createNote: { id: 'new-note-id' },
              createMeeting: { id: 'new-meeting-id' },
            },
          }),
        });
      });

      // Override strategy for this test
      process.env.FIREFLIES_SUMMARY_STRATEGY = 'immediate_only';

      const result = await main(payload, { 'x-hub-signature': signature, body });

      // Should only fetch once with immediate_only strategy
      expect(fetchCount).toBe(1);
      expect(result.success).toBe(true);
      expect(result.summaryPending).toBe(true);

      // Reset to default
      process.env.FIREFLIES_SUMMARY_STRATEGY = 'immediate_with_retry';
    });
  });

  describe('CRM Record Creation', () => {
    it('should create summary-focused notes for 1-on-1 meetings', async () => {
      const payload: FirefliesWebhookPayload = {
        meetingId: 'test-meeting-001',
        eventType: 'Transcription completed',
      };

      const body = JSON.stringify(payload);
      const signature = generateHMACSignature(body, 'test_webhook_secret');

      const createNoteMock = jest.fn();

      global.fetch = jest.fn().mockImplementation((url: string, options?: any) => {
        if (url === 'https://api.fireflies.ai/graphql') {
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({
              data: { transcript: mockFirefliesApiResponseWithSummary }, // Use raw API format
            }),
          });
        }

        // Twenty API
        const body = options?.body ? JSON.parse(options.body) : {};
        if (body.query?.includes('createNote')) {
          createNoteMock(body.variables);
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({
              data: { createNote: { id: 'new-note-id' } },
            }),
        });
      }

      return Promise.resolve({
          ok: true,
          json: () => Promise.resolve({
            data: {
              meetings: { edges: [] },
              people: { edges: [] },
              createPerson: { id: 'new-person-id' },
              createMeeting: { id: 'new-meeting-id' },
            },
          }),
        });
      });

      const result = await main(payload, { 'x-hub-signature': signature, body });

      expect(result.success).toBe(true);
      expect(createNoteMock).toHaveBeenCalled();

      const noteData = createNoteMock.mock.calls[0][0];
      expect(noteData.data.title).toContain('Meeting:');
      expect(noteData.data.bodyV2.markdown).toContain('## Overview'); // Markdown header, not bold
      expect(noteData.data.bodyV2.markdown).toContain('## Action Items'); // Markdown header, not bold
      expect(noteData.data.bodyV2.markdown).toContain('**Sentiment:**'); // This is bold
      expect(noteData.data.bodyV2.markdown).toContain('[View Full Transcript]');
    });

    it('should create meeting records for multi-party meetings', async () => {
      const payload: FirefliesWebhookPayload = {
        meetingId: 'test-team-003',
        eventType: 'Transcription completed',
      };

      const body = JSON.stringify(payload);
      const signature = generateHMACSignature(body, 'test_webhook_secret');

      const createMeetingMock = jest.fn();

      global.fetch = jest.fn().mockImplementation((url: string, options?: any) => {
        if (url === 'https://api.fireflies.ai/graphql') {
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({
              data: { transcript: mockFirefliesApiResponseTeamMeeting }, // Use raw API format
            }),
          });
        }

        // Twenty API
        const body = options?.body ? JSON.parse(options.body) : {};
        if (body.query?.includes('createMeeting')) {
          createMeetingMock(body.variables);
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({
              data: { createMeeting: { id: 'new-meeting-id' } },
            }),
          });
        }
        if (body.query?.includes('createNote')) {
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({
              data: { createNote: { id: 'new-note-id' } },
            }),
          });
        }

        return Promise.resolve({
          ok: true,
          json: () => Promise.resolve({
            data: {
              meetings: { edges: [] },
              people: { edges: [] },
              createPerson: { id: 'new-person-id' },
            },
          }),
        });
      });

      const result = await main(payload, { 'x-hub-signature': signature, body });

      expect(result.success).toBe(true);
      expect(result.meetingId).toBeDefined();
      expect(createMeetingMock).toHaveBeenCalled();
    });
  });

  describe('Error Handling & Resilience', () => {
    it('should never throw uncaught exceptions', async () => {
      const payload: FirefliesWebhookPayload = {
        meetingId: 'test-critical-error',
        eventType: 'Transcription completed',
      };

      const body = JSON.stringify(payload);
      const signature = generateHMACSignature(body, 'test_webhook_secret');

      global.fetch = jest.fn().mockImplementation(() => {
        throw new Error('Critical failure');
      });

      await expect(main(payload, { 'x-hub-signature': signature, body })).resolves.toEqual(
        expect.objectContaining({ success: false, errors: expect.any(Array) })
      );
    });

    it('should handle missing payload gracefully', async () => {
      const result = await main(null as any, {});

      expect(result.success).toBe(false);
      expect(result.errors).toBeDefined();
    });

    it('should handle invalid payload structure', async () => {
      const invalidPayload = { invalid: 'data' };

      const result = await main(invalidPayload as any, {});

    expect(result.success).toBe(false);
    expect(result.errors).toBeDefined();
  });
});
});
